<template>
  <div class="export-container">
    <el-dropdown size="small" type="primary" @command="toExport">
      <span class="export-dropdown-link">
        导出<i class="el-icon-arrow-down el-icon--right"></i>
      </span>
      <el-dropdown-menu slot="dropdown">
        <el-dropdown-item command="default">默认风格</el-dropdown-item>
        <el-dropdown-item command="officialDocument">公文风格</el-dropdown-item>
      </el-dropdown-menu>
    </el-dropdown>
    <el-dialog title="打印预览" :visible.sync="preview" width="700px" append-to-body @opened="onOpened">
      <div ref="previewDom" class="export-preview" :class="this.exportType">
        <parser v-if="formType === 10" class="export-form" :key="new Date().getTime()"
          :form-conf="conf" />
        <async-biz-form-component v-else-if="formType === 20" class="export-form"
          :process-instance-id="processInstance.id"></async-biz-form-component>
        <!-- 复制HTMLElement，没有vue组件状态 -->
        <div v-else-if="target" id="targetContainer">
        </div>
        <component v-else-if="formComponent.name" :is="formComponent.name" class="export-form"
          v-bind="formComponent.props || {}"></component>
        <el-image v-move v-if="url" :src="url" fit="fill" class="export-seal-image">
          <div slot="error" class="export-seal-image-error">
            <i class="el-icon-picture-outline"></i>
          </div>
        </el-image>
      </div>
      <div slot="footer" class="export-footer">
        <el-select class="export-seal" v-model="currSeal" placeholder="请选择签章" clearable filterable
          style="margin-right: 10px;">
          <el-option class="export-seal__item" v-for="item in sealList" :key="item.id"
            :value="item.url" :label="item.name">
            <span>{{ item.name }}</span><image-preview :src="item.url" width="50px"></image-preview>
          </el-option>
        </el-select>

        <el-button @click="preview = false">取消</el-button>
        <el-button type="primary" :loading="loading" @click="exportPDF">导出pdf</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import Vue from "vue";
import html2pdf from "html2pdf.js";
// import { jsPDF } from 'jspdf';
// import loadScript from "@/utils/loadScript";
import cloneDeep from "lodash/cloneDeep";
import Parser from "@/components/parser";
import ImagePreview from '@/components/ImagePreview/index.vue';
import { getSealAllList } from "@/api/system/seal";
import { decodeFields } from "@/utils/formGenerator";
import { getFileUrl } from '@/config/env';

let worker = null;

export default {
  components: {
    Parser,
    ImagePreview,
  },
  props: {
    processInstance: {
      type: Object,
      default: () => ({}),
    },
    target: {
      type: String,
      default: '',
    },
    formComponent: {
      type: Object,
      default: () => ({}),
    },
    fileName: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      exportType: "default",
      preview: false, //
      currSeal: '',
      sealList: [],
      loading: false,
    };
  },
  computed: {
    // html2pdf 的配置
    name() {
      return this.processInstance.name || this.fileName || "";
    },
    processDefinition() {
      return this.processInstance.processDefinition || {};
    },
    customViewPath() {
      const { processDefinition = {}, businessKey = '', id = '' } = this.processInstance;
      return processDefinition?.formCustomViewPath +
        '?id=' +
        businessKey + '&processInstanceId=' + id;
    },
    formType() {
      return this.processDefinition.formType || 0;
    },

    conf() {
      // const { fields, ...rest } = this.formConf;
      if (this.processDefinition.formFields) {
        const fields = decodeFields(
          this.processDefinition.formFields,
          this.processInstance.formVariables
        );
        const formConf = JSON.parse(this.processDefinition.formConf);
        return {
          ...formConf,
          fields:
            this.exportType === "officialDocument"
              ? this.fillSpan(cloneDeep(fields))
              : fields,
          disabled: true, // 表单不禁用，通过样式禁用，避免禁止状态下字体颜色不对
          noPlaceholder: true, // 不显示提示信息
          formBtns: false, // 按钮隐藏
          // rowType: "flex",
        };
      }
      return {};
    },
    url() {
      let url = this.currSeal || "";
      return url.includes(process.env.VUE_APP_ENV_URL)
        ? url.replace(process.env.VUE_APP_ENV_URL, window.location.origin)
        : url;
    },
  },
  watch: {
    processDefinition(val) {
      this.$nextTick(() => {
        this.requireComponent(val?.formCustomViewPath);
      });
    },
    formComponent: {
      handler(val) {
        this.$nextTick(() => {
          this.registryComponent(val?.name, val?.path);
        });
      },
      immediate: true,
    },
  },
  created() {
    worker = new html2pdf.Worker();
    // worker = new jsPDF();
    this.getSealAllList();
  },
  beforeDestroy() {
    worker = null;
  },
  methods: {
    requireComponent(formCustomViewPath) {
      const customViewPath = formCustomViewPath || (this.processDefinition?.formCustomViewPath ?? '');
      if (customViewPath && this.formType === 20) {
        this.registryComponent("async-biz-form-component", customViewPath)
      }
    },
    registryComponent(componentName, componentPath) {
      if (componentName) {
        if (!Vue.component(componentName)) {
          Vue.component(componentName, function (resolve) {
            require([`@/views${componentPath}.vue`], resolve);
          });
        }
      }
    },
    onOpened() {
      if (this.target) {
        // 直接导出
        const dom = document.querySelector(this.target);
        const container = document.getElementById('targetContainer');

        if (dom && container) {
          container.innerHTML = '';
          const domClone = dom.cloneNode(true);
          domClone.classList.add('export-form');
          container.appendChild(domClone);
        } else {
          console.warn("未找到目标节点");
        }
      }

      this.$emit('on-opened');
    },
    /* 导出表单为pdf */
    toExport(type) {
      this.requireComponent(this.processDefinition?.formCustomViewPath);
      this.registryComponent(this.formComponent.name, this.formComponent.path);

      this.$emit('before-export', type);

      this.$nextTick(() => {
        this.exportType = type;
        this.preview = true;
      });
    },
    opt() {
      return {
        margin: 0.5,
        filename: (this.name || "my-form") + "_" + Date.now() + ".pdf",
        pagebreak: { mode: ['css', 'legacy'], before: ['page-break-before'], after: [".page-break"], avoid: ['.el-form-item', '.page-not-break'] },
        image: { type: "jpeg", quality: 0.98 },
        html2canvas: { /* allowTaint: true,  */
          scale: 1,
        },
        jsPDF: { unit: "in", format: "a4", orientation: "portrait" },
        enableLinks: true,
      };
    },
    async exportPDF(target) {
      this.loading = true;
      await worker
        .set(this.opt())
        .from(this.$refs.previewDom)
        .toContainer()
        .toCanvas()
        .toImg()
        .toPdf()
        .save();
      // html2pdf(this.$refs.previewDom, opt);
      // worker.toPdf();
      // jspdf
      // await worker.html(this.$refs.previewDom).save((this.name || "my-form") + "_" + Date.now() + ".pdf")
      this.loading = false;
    },
    /* 补齐行列，避免公文风格，边框不对齐 */
    fillSpan(fields) {
      let spanTotal = 0;
      let lastItem = null;
      for (let i = 0; i < fields.length; i++) {
        const { __config__ } = fields[i];
        if (__config__.span) {
          spanTotal += __config__.span;
        }
        // 当前元素，将会换行显示，将上一个元素占用的栅格数补齐
        lastItem = i > 0 ? fields[i - 1] : null;
        if (spanTotal > 24 && lastItem) {
          lastItem.__config__.span += 24 - (spanTotal - __config__.span);
          // 完成一次补齐，设置 spanTotal 为当前元素 span 值，继续
          spanTotal = __config__.span;
        }
        // 最后一项补齐
        if (i === fields.length - 1) {
          // 不足补齐
          if (spanTotal <= 24) {
            __config__.span = 24 - (spanTotal - __config__.span);
          } else {
            // 超出，实际不会出现，上面处理了：最后一项换行，它的前一项补齐
            lastItem.__config__.span = 24 - (spanTotal - __config__.span);
            __config__.span = 24;
          }
        }
        // 子元素存在，也这样进行
        if (__config__.children && __config__.children.length) {
          __config__.children = this.fillSpan(__config__.children);
        }
      }
      return fields;
    },
    getSealAllList() {
      getSealAllList().then(({ data }) => {
        this.sealList = (data || []).map((item) => ({ ...item, url: getFileUrl(item.url) }));
      });
    },
  },
};
</script>

<style lang="scss">
$border: 1px solid #bbb;

.export-container {
  display: inline-block;
}

.export-dropdown-link {
  cursor: pointer;
  color: #409eff;
}

.export-footer {
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

.export-seal__item {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.export-seal-image {
  position: absolute;
  z-index: 999;
  cursor: pointer;

  height: 160px;
  width: 160px;
  right: 20px;
  bottom: 20px;
}

.export-preview {
  min-height: 300px;
  position: relative;
  margin: auto;

  .export-form {
    width: 100% !important;
    min-width: 640px !important; // window a4纸大小 794px，mac a4 为595px
    // margin: auto;
  }

  .export-form * {
    // pointer-events: none;
    color: #333 !important;
    background-color: transparent !important;

    &::after {
      color: inherit !important;
    }
  }

  .el-input-number,
  .el-input-number--medium {
    width: auto;
  }

  ::-webkit-input-placeholder {
    color: transparent !important;
    opacity: 0 !important;
  }

  :-ms-input-placeholder {
    color: transparent !important;
    opacity: 0 !important;
  }

  ::-moz-placeholder {
    color: transparent !important;
    opacity: 0 !important;
  }

  ::placeholder {
    color: transparent !important;
    opacity: 0 !important;
  }

  input,
  textarea,
  select {
    line-height: 1.5 !important;
    height: 24px !important;
    padding-top: 6px;
  }

  .distpicker-address-wrapper select {
    height: 32px !important;
    padding-top: 8px;
  }

  .el-checkbox__label {
    white-space: normal;
  }

  .page-break {
    break-after: page;
  }

  .page-break-before {
    break-before: page;
  }

  .page-not-break {
    break-inside: avoid;
  }

  &.officialDocument {
    // margin: 0 20px;

    * {
      border: none;
      // color: #fff;
      // background-color: transparent;
    }

    .el-radio__inner,
    .el-checkbox__inner {
      border: $border;
    }

    .el-row {
      border-bottom: $border;
      border-right: $border;
      border-left: $border;

      >* {

        border-top: $border;
      }
    }

    .el-col {
      border-top: $border;
      border-left: $border;
      border-right: $border;

      // 嵌套
      >* {
        border: none;
      }

      >.el-form-item:not(:last-child)>.el-form-item__content {
        border-bottom: $border;
      }
    }

    .el-form-item {
      margin-bottom: 0;
    }

    .el-form-item__content {
      border-left: $border;

      >.el-checkbox-group,
      >.el-radio-group,
      >.page-tips {
        padding: 0 10px;
      }
    }

    .print-padding {
      padding: 0 10px;
    }

    .el-form-item__label:before {
      display: none;
    }

    .el-input-number__increase,
    .el-input-number__decrease,
    .tox-editor-header,
    .tox-statusbar,
    .un-d-table-btn,
    .un-esign-btns,
    .el-input__count,
    .el-input__icon,
    .el-button {
      display: none;
    }

    .un-d-tag {

      .el-button,
      .el-tag__close {
        display: none;
      }
    }

    .un-list-panel {
      padding: 0;
    }

    .no-border-wrap {
      border: none;

      .el-row,
      .el-col,
      .el-form-item__content {
        border: none;
      }

      .el-row>* {
        border: none;
      }
    }
  }

}
</style>
